home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 1 Issue 2 / PDCD-1 - Issue 02.iso / _utilities / utilities / 001 / fue / c / BUFFER < prev    next >
Text File  |  1991-06-08  |  22KB  |  636 lines

  1. /*  BUFFER.C:   buffer mgmt. routines
  2.                 MicroEMACS 3.10
  3.  
  4.  * Buffer management.
  5.  * Some of the functions are internal,
  6.  * and some are actually attached to user
  7.  * keys. Like everyone else, they set hints
  8.  * for the display system.
  9.  */
  10.  
  11. /*      Modifications:
  12.         11-Sep-89       Mike Burrow (INMOS)     Added folding.
  13. */
  14.  
  15. #include        <stdio.h>
  16. #include        "estruct.h"
  17. #include        "etype.h"
  18. #include        "edef.h"
  19. #include        "elang.h"
  20.  
  21. /*
  22.  * Attach a buffer to a window. The
  23.  * values of dot and mark come from the buffer
  24.  * if the use count is 0. Otherwise, they come
  25.  * from some other window.
  26.  */
  27. /*{{{  PASCAL NEAR usebuffer(f, n)*/
  28. PASCAL NEAR usebuffer(f, n)
  29. {
  30.         register BUFFER *bp;    /* temporary buffer pointer */
  31.  
  32.         /* get the buffer name to switch to */
  33.         bp = getdefb();
  34.         bp = getcbuf(TEXT24, bp ? bp->b_bname : "main", TRUE);
  35. /*                          "Use buffer" */
  36.         if (!bp)
  37.                 return(ABORT);
  38.  
  39.         /* make it invisable if there is an argument */
  40.         if (f == TRUE)
  41.                 bp->b_flag |= BFINVS;
  42.  
  43.         /* switch to it in any case */
  44.         return(swbuffer(bp));
  45. }
  46. /*}}}*/
  47.  
  48. /* switch to the next buffer in the buffer list */
  49.  
  50. /*{{{  PASCAL NEAR nextbuffer(f, n)*/
  51. PASCAL NEAR nextbuffer(f, n)
  52.  
  53. int f, n;       /* default flag, numeric argument */
  54. {
  55.         register BUFFER *bp;    /* current eligable buffer */
  56.         register int status;
  57.  
  58.         /* make sure the arg is legit */
  59.         if (f == FALSE)
  60.                 n = 1;
  61.         if (n < 1)
  62.                 return(FALSE);
  63.  
  64.         /* cycle thru buffers until n runs out */
  65.         while (n-- > 0) {
  66.                 bp = getdefb();
  67.                 if (bp == NULL)
  68.                         return(FALSE);
  69.                 status = swbuffer(bp);
  70.                 if (status != TRUE)
  71.                         return(status);
  72.         }
  73.         return(status);
  74. }
  75. /*}}}*/
  76.  
  77. /* make buffer BP current */
  78.  
  79. /*{{{  PASCAL NEAR swbuffer(bp)*/
  80. PASCAL NEAR swbuffer(bp)
  81.  
  82. BUFFER *bp;
  83.  
  84. {
  85.         register WINDOW *wp;
  86.         register int cmark;             /* current mark */
  87.  
  88.         /* let a user macro get hold of things...if he wants */
  89.         execkey(&exbhook, FALSE, 1);
  90.  
  91.         if (--curbp->b_nwnd == 0) {             /* Last use.            */
  92.                 curbp->b_dotp  = curwp->w_dotp;
  93.                 curbp->b_doto  = curwp->w_doto;
  94.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  95.                         curbp->b_markp[cmark] = curwp->w_markp[cmark];
  96.                         curbp->b_marko[cmark] = curwp->w_marko[cmark];
  97.                 }
  98.                 curbp->b_fcol  = curwp->w_fcol;
  99.         }
  100.         curbp = bp;                             /* Switch.              */
  101.         if (curbp->b_active != TRUE) {          /* buffer not active yet*/
  102.                 /* read it in and activate it */
  103.                 readin(curbp->b_fname, TRUE);
  104.                 curbp->b_dotp = lforw(curbp->b_linep);
  105.                 curbp->b_doto = 0;
  106.                 curbp->b_active = TRUE;
  107.         }
  108.         curwp->w_bufp  = bp;
  109.         curwp->w_linep = bp->b_linep;           /* For macros, ignored. */
  110.         curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty.         */
  111.         if (bp->b_nwnd++ == 0) {                /* First use.           */
  112.                 curwp->w_dotp  = bp->b_dotp;
  113.                 curwp->w_doto  = bp->b_doto;
  114.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  115.                         curwp->w_markp[cmark] = bp->b_markp[cmark];
  116.                         curwp->w_marko[cmark] = bp->b_marko[cmark];
  117.                 }
  118.                 curwp->w_fcol  = bp->b_fcol;
  119.         } else {
  120.                 wp = wheadp;                    /* Look for old */
  121.                 while (wp != NULL) {
  122.                         if (wp!=curwp && wp->w_bufp==bp) {
  123.                                 curwp->w_dotp  = wp->w_dotp;
  124.                                 curwp->w_doto  = wp->w_doto;
  125.                                 for (cmark = 0; cmark < NMARKS; cmark++) {
  126.                                         curwp->w_markp[cmark] = wp->w_markp[cmark];
  127.                                         curwp->w_marko[cmark] = wp->w_marko[cmark];
  128.                                 }
  129.                                 curwp->w_fcol  = wp->w_fcol;
  130.                                 break;
  131.                         }
  132.                         wp = wp->w_wndp;
  133.                 }
  134.         }
  135.  
  136.         /* let a user macro get hold of things...if he wants */
  137.         execkey(&bufhook, FALSE, 1);
  138.  
  139.         return(TRUE);
  140. }
  141. /*}}}*/
  142.  
  143. /*
  144.  * Dispose of a buffer, by name.
  145.  * Ask for the name. Look it up (don't get too
  146.  * upset if it isn't there at all!). Get quite upset
  147.  * if the buffer is being displayed. Clear the buffer (ask
  148.  * if the buffer has been changed). Then free the header
  149.  * line and the buffer header. Bound to "C-X K".
  150.  */
  151. PASCAL NEAR killbuffer(f, n)
  152.  
  153. {
  154.         register BUFFER *bp;    /* ptr to buffer to dump */
  155.  
  156.         /* get the buffer name to kill */
  157.         bp = getdefb();
  158.         bp = getcbuf(TEXT26, bp ? bp->b_bname : "main", TRUE);
  159. /*                   "Kill buffer" */
  160.         if (bp == NULL)
  161.                 return(ABORT);
  162.  
  163.         return(zotbuf(bp));
  164. }
  165.  
  166. BUFFER *PASCAL NEAR getdefb()   /* get the default buffer for a use or kill */
  167.  
  168. {
  169.         BUFFER *bp;     /* default buffer */
  170.  
  171.         /* Find the next buffer, which will be the default */
  172.         bp = curbp->b_bufp;
  173.  
  174.         /* cycle through the buffers to find an eligable one */
  175.         while (bp == NULL || bp->b_flag & BFINVS) {
  176.                 if (bp == NULL)
  177.                         bp = bheadp;
  178.                 else
  179.                         bp = bp->b_bufp;
  180.  
  181.                 /* don't get caught in an infinite loop! */
  182.                 if (bp == curbp) {
  183.                         bp = NULL;
  184.                         break;
  185.                 }
  186.         }               
  187.         return(bp);
  188. }
  189.  
  190. PASCAL NEAR zotbuf(bp)  /* kill the buffer pointed to by bp */
  191.  
  192. register BUFFER *bp;
  193.  
  194. {
  195.         register BUFFER *bp1;
  196.         register BUFFER *bp2;
  197.         register int    s;
  198.  
  199.         if (bp->b_nwnd != 0) {                  /* Error if on screen.  */
  200.                 mlwrite(TEXT28);
  201. /*                      "Buffer is being displayed" */
  202.                 return(FALSE);
  203.         }
  204.         if ((s=bclear(bp)) != TRUE)             /* Blow text away.      */
  205.                 return(s);
  206.         free((char *) bp->b_linep);             /* Release header line. */
  207.         bp1 = NULL;                             /* Find the header.     */
  208.         bp2 = bheadp;
  209.         while (bp2 != bp) {
  210.                 bp1 = bp2;
  211.                 bp2 = bp2->b_bufp;
  212.         }
  213.         bp2 = bp2->b_bufp;                      /* Next one in chain.   */
  214.         if (bp1 == NULL)                        /* Unlink it.           */
  215.                 bheadp = bp2;
  216.         else
  217.                 bp1->b_bufp = bp2;
  218.         free((char *) bp);                      /* Release buffer block */
  219.         return(TRUE);
  220. }
  221.  
  222. PASCAL NEAR namebuffer(f,n)     /*      Rename the current buffer       */
  223.  
  224. int f, n;               /* default Flag & Numeric arg */
  225.  
  226. {
  227.         register BUFFER *bp;    /* pointer to scan through all buffers */
  228.         char bufn[NBUFN];       /* buffer to hold buffer name */
  229.  
  230.         /* prompt for and get the new buffer name */
  231. ask:    if (mlreply(TEXT29, bufn, NBUFN) != TRUE)
  232. /*                  "Change buffer name to: " */
  233.                 return(FALSE);
  234.  
  235.         /* and check for duplicates */
  236.         bp = bheadp;
  237.         while (bp != NULL) {
  238.                 if (bp != curbp) {
  239.                         /* if the names the same */
  240.                         if (strcmp(bufn, bp->b_bname) == 0)
  241.                                 goto ask;  /* try again */
  242.                 }
  243.                 bp = bp->b_bufp;        /* onward */
  244.         }
  245.  
  246.         strcpy(curbp->b_bname, bufn);   /* copy buffer name to structure */
  247.         curwp->w_flag |= WFMODE;        /* make mode line replot */
  248.         mlerase();
  249.         return(TRUE);
  250. }
  251.  
  252. /*
  253.         List all of the active buffers.  First update the special
  254.         buffer that holds the list.  Next make sure at least 1
  255.         window is displaying the buffer list, splitting the screen
  256.         if this is what it takes.  Lastly, repaint all of the
  257.         windows that are displaying the list.  Bound to "C-X C-B". 
  258.         A numeric argument forces it to list invisable buffers as
  259.         well.
  260. */
  261.  
  262. PASCAL NEAR listbuffers(f, n)
  263. {
  264.         register WINDOW *wp;
  265.         register BUFFER *bp;
  266.         register int    s;
  267.         register int cmark;             /* current mark */
  268.  
  269.         if ((s=makelist(f)) != TRUE)
  270.                 return(s);
  271.         if (blistp->b_nwnd == 0) {              /* Not on screen yet.   */
  272.                 if ((wp=wpopup()) == NULL)
  273.                         return(FALSE);
  274.                 bp = wp->w_bufp;
  275.                 if (--bp->b_nwnd == 0) {
  276.                         bp->b_dotp  = wp->w_dotp;
  277.                         bp->b_doto  = wp->w_doto;
  278.                         for (cmark = 0; cmark < NMARKS; cmark++) {
  279.                                 bp->b_markp[cmark] = wp->w_markp[cmark];
  280.                                 bp->b_marko[cmark] = wp->w_marko[cmark];
  281.                         }
  282.                         bp->b_fcol  = wp->w_fcol;
  283.                 }
  284.                 wp->w_bufp  = blistp;
  285.                 ++blistp->b_nwnd;
  286.         }
  287.         wp = wheadp;
  288.         while (wp != NULL) {
  289.                 if (wp->w_bufp == blistp) {
  290.                         wp->w_linep = lforw(blistp->b_linep);
  291.                         wp->w_dotp  = lforw(blistp->b_linep);
  292.                         wp->w_doto  = 0;
  293.                         for (cmark = 0; cmark < NMARKS; cmark++) {
  294.                                 wp->w_markp[cmark] = NULL;
  295.                                 wp->w_marko[cmark] = 0;
  296.                         }
  297.                         wp->w_flag |= WFMODE|WFHARD;
  298.                 }
  299.                 wp = wp->w_wndp;
  300.         }
  301.         return(TRUE);
  302. }
  303.  
  304. /*
  305.  * This routine rebuilds the
  306.  * text in the special secret buffer
  307.  * that holds the buffer list. It is called
  308.  * by the list buffers command. Return TRUE
  309.  * if everything works. Return FALSE if there
  310.  * is an error (if there is no memory). Iflag
  311.  * indecates weather to list hidden buffers.
  312.  */
  313. PASCAL NEAR makelist(iflag)
  314.  
  315. int iflag;      /* list hidden buffer flag */
  316.  
  317. {
  318.         register char   *cp1;
  319.         register char   *cp2;
  320.         register int    c;
  321.         register BUFFER *bp;
  322.         register LINE   *lp;
  323.         register int    s;
  324.         register int    i;
  325.         long nbytes;            /* # of bytes in current buffer */
  326.         char b[7+1];
  327.         char line[128];
  328.  
  329.         blistp->b_flag &= ~BFCHG;               /* Don't complain!      */
  330.         if ((s=bclear(blistp)) != TRUE)         /* Blow old text away   */
  331.                 return(s);
  332.         strcpy(blistp->b_fname, "");
  333.         if (addline(TEXT30) == FALSE
  334. /*                  "ACT   Modes      Size Buffer          File" */
  335.         ||  addline("--- --------- ------- --------------- ----") == FALSE)
  336.                 return(FALSE);
  337.         bp = bheadp;                            /* For all buffers      */
  338.  
  339.         /* build line to report global mode settings */
  340.         cp1 = &line[0];
  341.         *cp1++ = ' ';
  342.         *cp1++ = ' ';
  343.         *cp1++ = ' ';
  344.         *cp1++ = ' ';
  345.  
  346.         /* output the mode codes */
  347.         for (i = 0; i < NUMMODES; i++)
  348.                 if (gmode & (1 << i))
  349.                         *cp1++ = modecode[i];
  350.                 else
  351.                         *cp1++ = '.';
  352.         strcpy(cp1, TEXT31);
  353. /*                  "         Global Modes" */
  354.         if (addline(line) == FALSE)
  355.                 return(FALSE);
  356.  
  357.         /* output the list of buffers */
  358.         while (bp != NULL) {
  359.                 /* skip invisable buffers if iflag is false */
  360.                 if (((bp->b_flag&BFINVS) != 0) && (iflag != TRUE)) {
  361.                         bp = bp->b_bufp;
  362.                         continue;
  363.                 }
  364.                 cp1 = &line[0];                 /* Start at left edge   */
  365.  
  366.                 /* output status of ACTIVE flag (has the file been read in? */
  367.                 if (bp->b_active == TRUE)    /* "@" if activated       */
  368.                         *cp1++ = '@';
  369.                 else
  370.                         *cp1++ = ' ';
  371.  
  372.                 /* output status of changed flag */
  373.                 if ((bp->b_flag&BFCHG) != 0)    /* "*" if changed       */
  374.                         *cp1++ = '*';
  375.                 else
  376.                         *cp1++ = ' ';
  377.  
  378.                 /* report if the file is truncated */
  379.                 if ((bp->b_flag&BFTRUNC) != 0)
  380.                         *cp1++ = '#';
  381.                 else
  382.                         *cp1++ = ' ';
  383.  
  384.                 *cp1++ = ' ';   /* space */
  385.  
  386.                 /* output the mode codes */
  387.                 for (i = 0; i < NUMMODES; i++) {
  388.                         if (bp->b_mode & (1 << i))
  389.                                 *cp1++ = modecode[i];
  390.                         else
  391.                                 *cp1++ = '.';
  392.                 }
  393.                 *cp1++ = ' ';                   /* Gap.                 */
  394.                 nbytes = 0L;                    /* Count bytes in buf.  */
  395.                 lp = lforw(bp->b_linep);
  396.                 while (lp != bp->b_linep) {
  397.                         nbytes += (long)llength(lp)+1L;
  398.                         lp = lforw(lp);
  399.                 }
  400.                 long_asc(b, 7, nbytes);             /* 6 digit buffer size. */
  401.                 cp2 = &b[0];
  402.                 while ((c = *cp2++) != 0)
  403.                         *cp1++ = c;
  404.                 *cp1++ = ' ';                   /* Gap.                 */
  405.                 cp2 = &bp->b_bname[0];          /* Buffer name          */
  406.                 while ((c = *cp2++) != 0)
  407.                         *cp1++ = c;
  408.                 *cp1++ = ' ';                   /* Gap.                 */
  409.                 cp2 = &bp->b_fname[0];          /* File name            */
  410.                 if (*cp2 != 0) {
  411.                         while (cp1 < &line[22+NBUFN])
  412.                                 *cp1++ = ' ';
  413.                         while ((c = *cp2++) != 0) {
  414.                                 if (cp1 < &line[128-1])
  415.                                         *cp1++ = c;
  416.                         }
  417.                 }
  418.                 *cp1 = 0;                       /* Add to the buffer.   */
  419.                 if (addline(line) == FALSE)
  420.                         return(FALSE);
  421.                 bp = bp->b_bufp;
  422.         }
  423.         return(TRUE);                          /* All done             */
  424. }
  425.  
  426. /* Translate a long to ascii form. Don't trust various systems
  427.    ltoa() routines.. they aren't consistand                             */
  428.  
  429. PASCAL NEAR long_asc(buf, width, num)
  430.  
  431. char   buf[];
  432. int    width;
  433. long   num;
  434.  
  435. {
  436.         buf[width] = 0;                         /* End of string.       */
  437.         while (num >= 10) {                     /* Conditional digits.  */
  438.                 buf[--width] = (int)(num%10L) + '0';
  439.                 num /= 10L;
  440.         }
  441.         buf[--width] = (int)num + '0';          /* Always 1 digit.      */
  442.         while (width != 0)                      /* Pad with blanks.     */
  443.                 buf[--width] = ' ';
  444. }
  445.  
  446. /*
  447.  * The argument "text" points to
  448.  * a string. Append this line to the
  449.  * buffer list buffer. Handcraft the EOL
  450.  * on the end. Return TRUE if it worked and
  451.  * FALSE if you ran out of room.
  452.  */
  453. PASCAL NEAR addline(text)
  454. char    *text;
  455. {
  456.         register LINE   *lp;
  457.         register int    i;
  458.         register int    ntext;
  459.  
  460.         ntext = strlen(text);
  461.         if ((lp=lalloc(ntext)) == NULL)
  462.                 return(FALSE);
  463.         lp->l_type = LNORMAL;           /* MJB: 11-Sep-89 */
  464.         lp->l_foldp = (LINE *)NULL;     /* MJB: 11-Sep-89 */
  465.         for (i=0; i<ntext; ++i)
  466.                 lputc(lp, i, text[i]);
  467.         blistp->b_linep->l_bp->l_fp = lp;       /* Hook onto the end    */
  468.         lp->l_bp = blistp->b_linep->l_bp;
  469.         blistp->b_linep->l_bp = lp;
  470.         lp->l_fp = blistp->b_linep;
  471.         if (blistp->b_dotp == blistp->b_linep)  /* If "." is at the end */
  472.                 blistp->b_dotp = lp;            /* move it to new line  */
  473.         return(TRUE);
  474. }
  475.  
  476. /*
  477.  * Look through the list of
  478.  * buffers. Return TRUE if there
  479.  * are any changed buffers. Buffers
  480.  * that hold magic internal stuff are
  481.  * not considered; who cares if the
  482.  * list of buffer names is hacked.
  483.  * Return FALSE if no buffers
  484.  * have been changed.
  485.  */
  486. PASCAL NEAR anycb()
  487. {
  488.         register BUFFER *bp;
  489.  
  490.         bp = bheadp;
  491.         while (bp != NULL) {
  492.                 if ((bp->b_flag&BFINVS)==0 && (bp->b_flag&BFCHG)!=0)
  493.                         return(TRUE);
  494.                 bp = bp->b_bufp;
  495.         }
  496.         return(FALSE);
  497. }
  498.  
  499. /*
  500.  * Find a buffer, by name. Return a pointer
  501.  * to the BUFFER structure associated with it.
  502.  * If the buffer is not found
  503.  * and the "cflag" is TRUE, create it. The "bflag" is
  504.  * the settings for the flags in in buffer.
  505.  */
  506. BUFFER *PASCAL NEAR bfind(bname, cflag, bflag)
  507.  
  508. register char   *bname; /* name of buffer to find */
  509. int cflag;              /* create it if not found? */
  510. int bflag;              /* bit settings for a new buffer */
  511.  
  512. {
  513.         register BUFFER *bp;
  514.         register BUFFER *sb;    /* buffer to insert after */
  515.         register LINE   *lp;
  516.         int             cmark;  /* current mark */
  517.         int             cfold;  /* current fold entry */ /* MJB: 11-Sep-89 */
  518.  
  519.         bp = bheadp;
  520.         while (bp != NULL) {
  521.                 if (strcmp(bname, bp->b_bname) == 0)
  522.                         return(bp);
  523.                 bp = bp->b_bufp;
  524.         }
  525.         if (cflag != FALSE) {
  526.                 if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
  527.                         return(NULL);
  528.                 if ((lp=lalloc(0)) == NULL) {
  529.                         free((char *) bp);
  530.                         return(NULL);
  531.                 }
  532.                 lp->l_type = LNORMAL;           /* MJB: 11-Sep-89 */
  533.                 lp->l_foldp = (LINE *)NULL;     /* MJB: 11-Sep-89 */
  534.                 /* find the place in the list to insert this buffer */
  535.                 if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
  536.                         /* insert at the beginning */
  537.                         bp->b_bufp = bheadp;
  538.                         bheadp = bp;
  539.                 } else {
  540.                         sb = bheadp;
  541.                         while (sb->b_bufp != NULL) {
  542.                                 if (strcmp(sb->b_bufp->b_bname, bname) > 0)
  543.                                         break;
  544.                                 sb = sb->b_bufp;
  545.                         }
  546.  
  547.                         /* and insert it */
  548.                         bp->b_bufp = sb->b_bufp;
  549.                         sb->b_bufp = bp;
  550.                 }
  551.  
  552.                 /* and set up the other buffer fields */
  553.                 bp->b_topline = NULL;
  554.                 bp->b_botline = NULL;
  555.                 bp->b_active = TRUE;
  556.                 bp->b_dotp  = lp;
  557.                 bp->b_doto  = 0;
  558.                 for (cmark = 0; cmark < NMARKS; cmark++) {
  559.                         bp->b_markp[cmark] = NULL;
  560.                         bp->b_marko[cmark] = 0;
  561.                 }
  562.                 bp->b_fcol = 0;
  563.                 bp->b_flag  = bflag;
  564.                 bp->b_mode  = gmode;
  565.                 bp->b_nwnd  = 0;
  566.                 bp->b_linep = lp;
  567.                 strcpy(bp->b_fname, "");
  568. #if RISCOS
  569.                 strcpy(bp->b_ftype, "");
  570. #endif
  571.                 strcpy(bp->b_bname, bname);
  572. #if     CRYPT
  573.                 bp->b_key[0] = 0;
  574. #endif
  575.                 bp->b_nfolds = 0;                          /* MJB: 11-Sep-89 */
  576.                 for (cfold = 0; cfold < NFOLDS; cfold++) { /* MJB: 11-Sep-89 */
  577.                         bp->b_folds[cfold].f_topline = NULL;
  578.                         bp->b_folds[cfold].f_botline = NULL;
  579.                 }
  580.                 lp->l_fp = lp;
  581.                 lp->l_bp = lp;
  582.         }
  583.         return(bp);
  584. }
  585.  
  586. /*
  587.  * This routine blows away all of the text
  588.  * in a buffer. If the buffer is marked as changed
  589.  * then we ask if it is ok to blow it away; this is
  590.  * to save the user the grief of losing text. The
  591.  * window chain is nearly always wrong if this gets
  592.  * called; the caller must arrange for the updates
  593.  * that are required. Return TRUE if everything
  594.  * looks good.
  595.  */
  596. PASCAL NEAR bclear(bp)
  597. register BUFFER *bp;
  598. {
  599.         register LINE   *lp;
  600.         register int    s;
  601.         int cmark;              /* current mark */
  602.  
  603.         if ((bp->b_flag&BFINVS) == 0            /* Not scratch buffer.  */
  604.         && (bp->b_flag&BFCHG) != 0              /* Something changed    */
  605.         && (s=mlyesno(TEXT32)) != TRUE)
  606. /*                    "Discard changes" */
  607.                 return(s);
  608.         bp->b_flag  &= ~BFCHG;                  /* Not changed          */
  609.         while ((lp=bp->b_linep->l_fp) != bp->b_linep)
  610.                 lfree(lp);
  611.         bp->b_dotp  = bp->b_linep;              /* Fix "."              */
  612.         bp->b_doto  = 0;
  613.         for (cmark = 0; cmark < NMARKS; cmark++) {
  614.                 bp->b_markp[cmark] = NULL;  /* Invalidate "mark"    */
  615.                 bp->b_marko[cmark] = 0;
  616.         }
  617.         bp->b_fcol = 0;
  618.         return(TRUE);
  619. }
  620.  
  621. PASCAL NEAR unmark(f, n)        /* unmark the current buffers change flag */
  622.  
  623. int f, n;       /* unused command arguments */
  624.  
  625. {
  626.         register WINDOW *wp;
  627.  
  628.         /* unmark the buffer */
  629.         curbp->b_flag &= ~BFCHG;
  630.  
  631.         /* unmark all windows as well */
  632.         upmode();
  633.  
  634.         return(TRUE);
  635. }
  636.